package cc.rengu.oltp.service.realize.impl;

import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.RspCodeMapMapper;
import cc.rengu.oltp.service.common.dao.impl.RspCodeMapMapperImpl;
import cc.rengu.oltp.service.common.entity.RspCodeMap;
import cc.rengu.oltp.service.common.enums.TransStatusEnum;
import cc.rengu.oltp.service.realize.RespCodeService;
import cc.rengu.oltp.utility.util.RedisUtil;
import cc.rengu.oltp.utility.util.StringUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.util.List;
import java.util.Optional;

/**
 * 错误码映射关系组件实现类
 * Created by wangcheng on 2021/3/16 10:14
 */
public class RespCodeServiceImpl implements RespCodeService {
    private final RgLogger rglog = RgLog.getLogger(this.getClass().getName());

    @Override
    public TransStatusEnum transferRespCode(String rspSysId, String rspCode, String rspMsg) {
        TransStatusEnum transStatusEnum = null;
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        try {
            String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
            String msgSrcId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID);
            String transChannelId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.CHANNEL_ID);
            String rspCodeScene = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.RSP_CODE_SCENE);
            rglog.info("业务响应码映射转换信息,法人行:<{}>,源系统标识:<{}>,源渠道标识:<{}>,错误码场景:<{}>,业务响应码所属系统:<{}>,错误信息:<{}-{}>", instId, msgSrcId, transChannelId, rspCodeScene, rspSysId, rspCode, rspMsg);
            /* Step1:根据法人行及源系统标识的业务渠道细分从Redis中查询错误码映射关系 */
            String rspCodeMapKey = instId.trim() + rspSysId.trim() + rspCode.trim();
            List<RspCodeMap> rspCodeMapList = JSON.parseArray(RedisUtil.hashGet(AppParamConstant.RSP_CODE_MAP_CACHE, rspCodeMapKey), RspCodeMap.class);
            /* Step2：若从缓存中找不到配置，则从数据库中查找当前法人行的配置 */
            RspCodeMapMapper rspCodeMapMapper = new RspCodeMapMapperImpl();
            if (null == rspCodeMapList || rspCodeMapList.isEmpty()) {
                rspCodeMapList = rspCodeMapMapper.selectRespCodeMapInfoBySrcRspCode(instId.trim(), rspSysId.trim(), rspCode.trim());
            }
            /* Step3：若从数据库中查找当前法人行的配置，则从缓存中查找默认法人行的配置 */
            if ((null == rspCodeMapList || rspCodeMapList.isEmpty()) && !instId.equals(AppParamConstant.DEFAULT_INSTID)) {
                rspCodeMapKey = AppParamConstant.DEFAULT_INSTID + rspSysId.trim() + rspCode.trim();
                rglog.info("使用业务渠道标识进行错误码映射：rspCodeMapKey: {}", rspCodeMapKey);
                rspCodeMapList = JSON.parseArray(RedisUtil.hashGet(AppParamConstant.RSP_CODE_MAP_CACHE, rspCodeMapKey), RspCodeMap.class);
                /* Step3.1：若从数据库中查找也找不到默认法人行的配置，则从数据库中查找默认法人行的配置 */
                if (null == rspCodeMapList || rspCodeMapList.isEmpty()) {
                    rspCodeMapList = rspCodeMapMapper.selectRespCodeMapInfoBySrcRspCode(AppParamConstant.DEFAULT_INSTID, rspSysId.trim(), rspCode.trim());
                }
            }
            /* Step4：根据错误码映射配置关系、源系统标识、源渠道标识及错误码业务场景转换错误码 */
            if (null != rspCodeMapList && !rspCodeMapList.isEmpty()) {
                String rspCodeSceneCode = (null == rspCodeScene) ? "00" : rspCodeScene;
                Optional<RspCodeMap> rspCodeMapOpt = rspCodeMapList.stream().filter(item -> item.getDestSysId().equals(msgSrcId) &&
                        item.getDestChannelId().equals(transChannelId) && item.getRspCodeScene().equals(rspCodeSceneCode)).findFirst();
                if (!rspCodeMapOpt.isPresent()) {
                    rglog.debug("未配置业务系统(模块){}业务响应码<{}-{}>到源系统<{}>对应渠道<{}>的错误码转换关系,查找源渠道标识为<{}>的错误码映射信息!",
                            rspSysId, rspCode, rspMsg, msgSrcId, transChannelId, msgSrcId);
                    rspCodeMapOpt = rspCodeMapList.stream().filter(item -> item.getDestSysId().equals(msgSrcId) &&
                            item.getDestChannelId().equals(msgSrcId) && item.getRspCodeScene().equals(rspCodeSceneCode)).findFirst();
                }
                if (rspCodeMapOpt.isPresent()) {
                    RspCodeMap rspCodeMap = rspCodeMapOpt.get();
                    xmlTreeUtil.setXmlTreeObjectValue(TreeNodeConstant.RSP_CODE_MAP, rspCodeMap);
                    rglog.info("交易状态{},业务响应信息<{}-{}>", rspCodeMap.getTransStatus(), rspCode, rspMsg);
                    xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_CODE, rspCodeMap.getDestRspCode());
                    if (!StringUtil.isEmptyOrNull(rspCodeMap.getDestRspDesc())) {
                        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_DESC, rspCodeMap.getDestRspDesc());
                    } else {
                        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_DESC, rspMsg);
                    }
                    if (TransStatusEnum.SYSTEM_REJECT.getStatus().equals(rspCodeMap.getTransStatus())) {
                        transStatusEnum = TransStatusEnum.SYSTEM_REJECT;
                    } else if (TransStatusEnum.TRANS_SUCC.getStatus().equals(rspCodeMap.getTransStatus())) {
                        transStatusEnum = TransStatusEnum.TRANS_SUCC;
                    } else if (TransStatusEnum.TRANS_TIMEOUT.getStatus().equals(rspCodeMap.getTransStatus())) {
                        transStatusEnum = TransStatusEnum.TRANS_TIMEOUT;
                    }
                } else {
                    rglog.error("未配置业务系统(模块){}业务响应码<{}-{}>到源系统<{}>对应渠道<{}>的错误码转换关系!", rspSysId, rspCode, rspMsg, msgSrcId, transChannelId);
                    rglog.debug("已经配置的错误码映射关系：{}", JSON.toJSONString(rspCodeMapList));
                }
            } else {
                rglog.error("未配置业务系统(模块){}业务响应码<{}-{}>的转换关系!", rspSysId, rspCode, rspMsg);
            }
        } catch (Exception e) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            rglog.error("业务响应码转换失败,rspSysId:<{}>,rspCode:<{}>,rspMsg:<{}>,异常信息:<{}>", rspSysId, rspCode, rspMsg, byteArrayOutputStream.toString());
        }
        return transStatusEnum;
    }
}
